#--
# Copyright (c) 2007 Maximilian Ott
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#++
require "config/environment"

module CopyrightSource
  
  DEFAULT_LICENSE = 'MIT-LICENSE'
  
  # Hash from file extension to comment delimeter.
  #
  SOURCE2COMMENT = {
    'rb' => '#',
    'mab' => '#',
    'wai' => '#',
    'rake' => '#'
  }
  
  SOURCE2COMMENT2 = {
    'rbx' => '#'
  }
  
  
  PREFIX = 'Copyright \(c\)'
  
  # Add copyright notice to all text file in application.
  #
  #  opts: 
  #    :plugin - Target specific plugin
  #    :license - Select specific license from :license_dir
  #    :owner - Replace the @OWNER@ tag in license with this string.
  def self.run(opts = {})
    if (plugin = opts[:plugin])
      top_dir = File.join(RAILS_ROOT, "vendor/plugins/#{plugin}")
    else 
      top_dir = File.join(RAILS_ROOT, "app")
    end
    
    # Read license file and replace place holders
    #
    lic_name = opts[:license] || DEFAULT_LICENSE
    lic_file = File.join(File.dirname(__FILE__), "../licenses/#{lic_name}")
    unless File.exists? lic_file
      raise "Can't find license file '#{lic_file}'"
    end
    license = File.read(lic_file)
    license.sub!(/@YEAR@/, opts[:year] || Date.today.year.to_s)    
    license.sub!(/@NAME@/, opts[:owner] || 'Unknown')
    
    # Find all relevant files and add copyright notice
    Dir.chdir(top_dir) do 
      pattern = File.join("**", "*.{#{SOURCE2COMMENT.keys.join(',')}}")
      Dir[pattern].each  do |f|
        puts ".. Processing #{f}"
        annotate_one_file f, license
      end
    end
    puts ".. Done"
  end
  
  # Add a copyright statement to a file. If the file already contains
  # such a statement (a comment starting
  # with "Copyright ..."), remove it first.
  #
  def self.annotate_one_file(file_name, copyright)
    if File.exist?(file_name)
      before, after = clean_file(file_name)
      # Remove old copyright
      #content.sub!(/^.*#{PREFIX}.*?\n(.*\n)*(.*#{POSTFIX}\n)+?/, '')

      # Write it back
      File.open(file_name, "w") do |f|
        before.each do |l|
          f.puts l
        end
        
        # First copyright notice
        f.puts '#--'
        copyright.each_line do |l|
          f.puts "# #{l}"
        end
        # end of copyright block
        f.puts "#++"
        
        # reminder of file
        after.each do |l|
          f.puts l
        end
      end
    end
  end
  
  # Read file +file_name+ and remove potential existing
  # copyright notice.
  #
  def self.clean_file(file_name)
    last_line = nil
    before = []
    after = []
    state = :before
    File.readlines(file_name).each do |l|
      #puts "line(#{state}): #{l}"
      case state
      when :before
        if l =~ /#{PREFIX}/
          state = :inside
          before << last_line unless !last_line.nil? && last_line =~ /#--/
        else
          before << last_line if last_line
        end
        last_line = l
      when :inside
        if l =~ /#\+\+/
          state = :after
        end
      when :after
        after << l
      end
    end
    #puts "before: #{before}"
    if state == :before && last_line
      before << last_line
    end
    state == :before ? [[], before] : [before, after]
  end
end
